#include <algorithm>
#include <cstdio>

const int N = 1e5 + 5, inf = 0x3f3f3f3f;
int n, m, tot, cnt, dfn[N], son[N], top[N], dep[N], siz[N], cvt[N], f[N];
int e_cnt, heads[N];

struct Edge {
  int v, nxt;
} e[N << 1];

inline void add(int u, int v) {
  e[++e_cnt].v = v, e[e_cnt].nxt = heads[u], heads[u] = e_cnt;
}

namespace SegTree {

struct Node {
  int val, tag;
} tr[N << 2];

inline void pushup(int x) {
  tr[x].val = std::max(tr[x << 1].val, tr[x << 1 | 1].val);
}

inline void pushdown(int x) {
  static int ls, rs;
  if (tr[x].tag) {
    ls = x << 1, rs = x << 1 | 1;
    tr[ls].tag += tr[x].tag;
    tr[rs].tag += tr[x].tag;
    tr[ls].val += tr[x].tag;
    tr[rs].val += tr[x].tag;
    tr[x].tag = 0;
  }
}

void build(int x, int l, int r) {
  if (l == r) return tr[x].val = dep[cvt[l]], void();
  int mid = (l + r) >> 1;
  build(x << 1, l, mid);
  build(x << 1 | 1, mid + 1, r);
  pushup(x);
}

void modify(int x, int l, int r, int L, int R, int v) {
  if (L <= l && r <= R) return tr[x].tag += v, tr[x].val += v, void();
  int mid = (l + r) >> 1;
  pushdown(x);
  if (L <= mid) modify(x << 1, l, mid, L, R, v);
  if (mid < R) modify(x << 1 | 1, mid + 1, r, L, R, v);
  pushup(x);
}

int query(int x, int l, int r, int L, int R) {
  if (L <= l && r <= R) return tr[x].val;
  int mid = (l + r) >> 1, res = -inf;
  pushdown(x);
  if (L <= mid) res = std::max(res, query(x << 1, l, mid, L, R));
  if (mid < R) res = std::max(res, query(x << 1 | 1, mid + 1, r, L, R));
  return res;
}

int query(int x, int l, int r, int pos) {
  if (l == r) return tr[x].val;
  int mid = (l + r) >> 1;
  pushdown(x);
  if (pos <= mid) return query(x << 1, l, mid, pos);
  else
    return query(x << 1 | 1, mid + 1, r, pos);
}
}  // namespace SegTree

namespace LCT {

struct Node {
  int ch[2], fa;
  bool rev;
} tr[N];

inline bool isnrt(int x) {
  return tr[tr[x].fa].ch[0] == x || tr[tr[x].fa].ch[1] == x;
}

inline bool iden(int x) { return tr[tr[x].fa].ch[1] == x; }

inline void rotate(int x) {
  bool xtofa = iden(x);
  int fa = tr[x].fa, ffa = tr[fa].fa, son = tr[x].ch[!xtofa];
  if (isnrt(fa)) tr[ffa].ch[iden(fa)] = x;
  tr[x].ch[!xtofa] = fa;
  tr[fa].ch[xtofa] = son;
  if (son) tr[son].fa = fa;
  tr[fa].fa = x;
  tr[x].fa = ffa;
}

inline void splay(int x) {
  for (int fa; isnrt(x); rotate(x)) {
    if (isnrt(fa = tr[x].fa)) rotate(iden(fa) == iden(x) ? fa : x);
  }
}

inline int findrt(int x) {
  while (tr[x].ch[0]) x = tr[x].ch[0];
  return x;
}

inline void access(int x) {
  for (int y = 0, ffa; x; y = x, x = tr[x].fa) {
    splay(x);
    if (tr[x].ch[1])
      ffa = findrt(tr[x].ch[1]),
      SegTree::modify(1, 1, n, dfn[ffa], dfn[ffa] + siz[ffa] - 1, 1);
    if ((tr[x].ch[1] = y))
      ffa = findrt(y),
      SegTree::modify(1, 1, n, dfn[ffa], dfn[ffa] + siz[ffa] - 1, -1);
  }
}
}  // namespace LCT

void dfs1(int x) {
  siz[x] = 1;
  for (int i = heads[x], v; i; i = e[i].nxt) {
    if ((v = e[i].v) != f[x]) {
      f[v] = LCT::tr[v].fa = x, dep[v] = dep[x] + 1;
      dfs1(v);
      siz[x] += siz[v];
      if (siz[son[x]] < siz[v]) son[x] = v;
    }
  }
}

void dfs2(int x) {
  dfn[x] = ++cnt, cvt[cnt] = x;
  if (son[x]) top[son[x]] = top[x], dfs2(son[x]);
  for (int i = heads[x], v; i; i = e[i].nxt) {
    if ((v = e[i].v) != LCT::tr[x].fa && v != son[x]) {
      top[v] = v;
      dfs2(v);
    }
  }
}

inline int lca(int x, int y) {
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) std::swap(x, y);
    x = f[top[x]];
  }
  if (dep[x] < dep[y]) std::swap(x, y);
  return y;
}

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen("testdata.in", "r", stdin);
  freopen("testdata.out", "w", stdout);
#else
  freopen("P3703 [SDOI2017]树点涂色.in", "r", stdin);
  freopen("P3703 [SDOI2017]树点涂色.out", "w", stdout);
#endif
#endif

  scanf("%d%d", &n, &m);
  int x, y;
  for (int i = 1; i < n; ++i) {
    scanf("%d%d", &x, &y);
    add(x, y);
    add(y, x);
  }
  dep[1] = 1, f[1] = 1, top[1] = 1;
  dfs1(1), dfs2(1);
  SegTree::build(1, 1, n);
  for (int i = 1, opt; i <= m; ++i) {
    scanf("%d%d", &opt, &x);
    switch (opt) {
      case 1:
        LCT::access(x);
        break;
      case 2:
        scanf("%d", &y);
        printf("%d\n", SegTree::query(1, 1, n, dfn[x]) +
                           SegTree::query(1, 1, n, dfn[y]) -
                           (SegTree::query(1, 1, n, dfn[lca(x, y)]) << 1) + 1);
        break;
      case 3:
        printf("%d\n", SegTree::query(1, 1, n, dfn[x], dfn[x] + siz[x] - 1));
    }
  }
  return 0;
}